
package com.example.filtransfer.client;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;

import com.example.filetransfer.publicsource.Log;
import com.example.filetransfer.publicsource.connection.DataReceiver;
import com.example.filetransfer.publicsource.connection.DataReceiver.onReceiveMessageListener;
import com.example.filetransfer.publicsource.connection.DataSender;
import com.example.filetransfer.publicsource.connection.FileTransferListener;
import com.example.filetransfer.publicsource.connection.NetBroadcast;
import com.example.filetransfer.publicsource.connection.NetBroadcastReceiver;
import com.example.filetransfer.publicsource.connection.NetBroadcastReceiver.MessageListener;
import com.example.filetransfer.publicsource.connection.Protocol;

public class ClientConnectionManager extends Thread implements onReceiveMessageListener,
        FileTransferListener {
    private static final String TAG = "ClientConnectionManager";
    private static ClientConnectionManager INSTANCE;
    private boolean mStopAccept = false;
    private Socket mSocket;
    private DataReceiver mDataReceiver;
    private DataSender mDataSender;
    private ServerSocket mServerSocket;
    private NetBroadcastReceiver mNetBroadcastReceiver;
    // TODO here need set port from user.
    private int mServerPort = Protocol.DEFAULT_SERVER_PORT;
    private volatile boolean mError = false;

    protected ClientConnectionManager() throws IOException {
        mDataSender = new DataSender(Protocol.SYNCDIR);
        mServerSocket = new ServerSocket(mServerPort);
        mNetBroadcastReceiver = new NetBroadcastReceiver(Protocol.BROADCAST_SERVER_LISTEN_PORT);
        NetBroadcast.getInstance();
        mNetBroadcastReceiver.setMessageListener(new MessageListener() {
            @Override
            public void onNewMessageReceive(String message) {
                if (Protocol.MESSAGE_SEND_SERVER_ADDRESS.equals(message)) {
                    Log.d(TAG, "Get MESSAGE_SEND_SERVER_ADDRESS");
//                    try {
                        //TODO get ip
//                        String ip = InetAddress.getLocalHost().getHostAddress();
                        String ip = "192.168.1.105";
                        // Send Server address.
                        NetBroadcast.getInstance().setIp(ip);
                        NetBroadcast.getInstance().sendBroadcast(
                                Protocol.BROADCAST_CLIENT_LISTEN_PORT,
                                Protocol.createServerAddress(ip, mServerPort));
//                    } catch (UnknownHostException e) {
//                        Log.e(TAG, "fatal error when get the ip address");
//                    }
                } else {
                    Log.d(TAG, "Get no useful message:" + message);
                }
            }
        });
        mNetBroadcastReceiver.start();
    };

    public static synchronized ClientConnectionManager getInstance() throws IOException {
        if (INSTANCE == null || INSTANCE.mError) {
            INSTANCE = new ClientConnectionManager();
            INSTANCE.start();
        }
        return INSTANCE;
    }

    @Override
    public void run() {
        System.out.println("temp ... running");
        while (!mStopAccept) {
            try {
                mSocket = mServerSocket.accept();
                Log.d(TAG, "New client accept...ip = " +  mSocket.getInetAddress());
                DataOutputStream outputStream = new DataOutputStream(mSocket.getOutputStream());
                mDataSender.setOutputStream(outputStream);
                mDataSender.start();
                DataInputStream mInputStream = new DataInputStream(mSocket.getInputStream());
                mDataReceiver = new DataReceiver(mInputStream);
                mDataReceiver.setMessageListener(this);
                mDataReceiver.setFileTransferListener(this);
                mDataReceiver.setRootDir(Protocol.SYNCDIR);
                // need not start, this thread is free;
                mDataReceiver.run();
            } catch (UnknownHostException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                mError = true;
                close();
            }
        }
    }

    public OutputStream getOutputStream(String ip) throws IOException {
        if (mSocket != null) {
            return mSocket.getOutputStream();
        } else {
            return null;
        }
    }

    public void close() {
        mStopAccept = true;
        if (mServerSocket != null) {
            try {
                mServerSocket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        if (mDataReceiver != null) {
            mDataReceiver.release();
        }
        if (mDataSender != null) {
            mDataSender.release();
        }
    }

    private FileTransferListener mFileTransferListener;
    private onReceiveMessageListener mMessageListener;

    public void setFilterTransferListener(FileTransferListener fileTransferListener) {
        this.mFileTransferListener = fileTransferListener;
    }

    public void setMessageListener(onReceiveMessageListener messageListener) {
        this.mMessageListener = messageListener;
    }

    public void sendData(String message) {
        mDataSender.sendMessage(message);
    }

    public void sendFile(String url, FileTransferListener listener) throws FileNotFoundException {
        mDataSender.sendFile(url, listener);
    }

    public void setRootDirPath(String path) {
        mDataReceiver.setRootDir(path);
    }

    @Override
    public void onProgressChanged(String fileUrl, int progress) {
        if (mFileTransferListener != null) {
            mFileTransferListener.onProgressChanged(fileUrl, progress);
        }
    }

    @Override
    public void receiveMessage(String message) {
        Log.d(TAG, "receive message:" + message);
        if (mMessageListener != null) {
            mMessageListener.receiveMessage(message);
        }
    }
}
